﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Configuration;
using System.Threading;
using ConversionInterface;
using DataAccess;

namespace IPConverter
{
    public partial class MainForm : ParentForm
    {
        #region Member Data
        private BindingList<MediaFile> mediaFiles = new BindingList<MediaFile>();
        private List<Thread> workerThreads = new List<Thread>();
        private ConvertMedia convert = new ConvertMedia();
        private MediaPersistence persistence = new MediaPersistence();
        private string tempOutputFilename = "";
        private bool disposed;
        #endregion

        #region Constructor
        public MainForm()
        {
            InitializeComponent();
            this.Load += new EventHandler(MainForm_Load);
            this.treeView1.NodeMouseClick += new TreeNodeMouseClickEventHandler(treeView1_NodeMouseClick);
            this.treeView1.BeforeExpand += new TreeViewCancelEventHandler(treeView1_BeforeExpand);
            this.dataGridView1.DragEnter += new DragEventHandler(dataGridView1_DragEnter);
            this.FormClosing += new FormClosingEventHandler(MainForm_FormClosing);
            this.treeView1.ItemDrag += new ItemDragEventHandler(treeView1_ItemDrag);
            this.dataGridView1.DragDrop += new DragEventHandler(dataGridView1_DragDrop);
            this.dataGridView1.RowsAdded += new DataGridViewRowsAddedEventHandler(dataGridView1_RowsAdded);
            this.convert.ConversionStageChanged += new ConvertMedia.OnConversionStageChange(convert_ConversionStageChanged);
            this.convert.ConversionComplete += new ConvertMedia.OnConversionComplete(convert_ConversionComplete);
            this.convert.ConversionPercentageChanged += new ConvertMedia.OnConversionPercentageChange(convert_ConversionPercentageChanged);
            Application.ApplicationExit +=new EventHandler(Application_ApplicationExit);
            Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
            this.dataGridView1.CellEndEdit += new DataGridViewCellEventHandler(dataGridView1_CellEndEdit);
            this.dataGridView1.CellBeginEdit += new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit);
            this.dataGridView1.DataError += new DataGridViewDataErrorEventHandler(dataGridView1_DataError);

        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Handles the ThreadException event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Threading.ThreadExceptionEventArgs"/> instance containing the event data.</param>
        void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            CleanUp();
        }
        /// <summary>
        /// Handles the ApplicationExit event of the Application control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void Application_ApplicationExit(object sender, EventArgs e)
        {
            CleanUp();
        }
        /// <summary>
        /// Handles the RowsAdded event of the dataGridView1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewRowsAddedEventArgs"/> instance containing the event data.</param>
        void dataGridView1_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e)
        {
            //since the Rows Added event is not reliable (apparently a bug), I do every single row
            foreach (DataGridViewRow row in this.dataGridView1.Rows)
            {
                if (row.Cells["Audio"].Value != null && row.Cells["Subtitle"].Value != null)
                    continue;

                MediaFile file = (MediaFile)row.DataBoundItem;
                DataGridViewComboBoxCell audioCB = (DataGridViewComboBoxCell)row.Cells["Audio"];
                DataGridViewComboBoxCell subCB = (DataGridViewComboBoxCell)row.Cells["Subtitle"];
                DataGridViewComboBoxCell targetCB = (DataGridViewComboBoxCell)row.Cells["Target"];

                audioCB.ValueMember = "Language";
                audioCB.DataSource = file.AvailableAudio;
                try
                {
                    audioCB.Value = file.ChosenAudio.Language;
                }
                catch (Exception) { }

                subCB.ValueMember = "Language";
                subCB.DataSource = file.AvailableSubs;
                try
                {
                    subCB.Value = file.ChosenSub.Language;
                }
                catch (Exception) { }

                targetCB.DataSource = System.Enum.GetNames(typeof(ConvertMedia.ConversionTarget));
                targetCB.Value = file.TargetDevice;
            }

        }
        /// <summary>
        /// Called the the Main Form is opened.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        void MainForm_Load(object sender, EventArgs e)
        {
            //if this is the first time the app has been opened, we're going to save the working directory
            string outputDirectory = this.config.AppSettings.Settings["OutputDirectory"].Value;
            if (outputDirectory.Trim() == "")
            {
                this.config.AppSettings.Settings["OutputDirectory"].Value = Application.StartupPath + "\\Converted Videos";
                this.config.Save(ConfigurationSaveMode.Modified);
            }

            List<MediaFile> jobs = this.persistence.GetJobs();
            foreach(MediaFile file in jobs)
                this.mediaFiles.Add(file);
            PopulateGrid();
            PopulateTree();
        }
        /// <summary>
        /// Called when the application is closed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.persistence.SaveJobs(this.mediaFiles.ToList<MediaFile>());
            CleanUp();
        }
        /// <summary>
        /// Called when the user drag and drops a node of the treeview into the grid
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        void dataGridView1_DragDrop(object sender, DragEventArgs e)
        {
            TreeNode node = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");
            DirectoryInfo directoryInfo = new DirectoryInfo(node.Name);
            FileInfo fileInfo = new FileInfo(node.Name);
            List<FileInfo> files = null;

            foreach (MediaFile file in mediaFiles)
            {
                if (file.InputFilename == node.Name)
                {
                    MessageBox.Show("This file is already in your queue.","Error",MessageBoxButtons.OK,MessageBoxIcon.Warning);
                    return;
                }
            }

            try
            {
                if (directoryInfo.Exists == false)
                {
                    MediaFile newFile = new MediaFile(node.Name);
                    mediaFiles.Add(newFile);
                }
                else
                {
                    files = this.GetFiles(node.Name);
                    foreach (FileInfo file in files)
                    {
                        MediaFile newFile = new MediaFile(file.FullName);
                        mediaFiles.Add(newFile);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("An error occurred while trying to add " + node.Text + ":\r\n\r\n" + ex.Message);
            }

            //this.PopulateGrid();
        }
        /// <summary>
        /// Called when the user drags a node of the treeview over the grid, but does not let go of the mouse yet
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
        void dataGridView1_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.Copy;
        }
        /// <summary>
        /// Called when the user clicks and drags a node of the treeview
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.ItemDragEventArgs"/> instance containing the event data.</param>
        void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            TreeNode node = e.Item as TreeNode;
            this.treeView1.DoDragDrop(e.Item, DragDropEffects.Copy);
            this.treeView1.SelectedNode = node;
        }
        /// <summary>
        /// Called when the + / - of a treenode is clicked, but before it actually expands
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.TreeViewCancelEventArgs"/> instance containing the event data.</param>
        void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(e.Node.Name);
            //if (e.Node.FirstNode != null && e.Node.FirstNode.Name == "dummy")
            //    e.Node.FirstNode.Remove();
            e.Node.Nodes.Clear();
            DirectoryInfo[] directories = null;
            try
            {
                directories = directoryInfo.GetDirectories();
            }
            catch (IOException)
            {
                return;
            }
            foreach (DirectoryInfo info in directories)
            {
                if (e.Node.Name.EndsWith("\\"))
                    PopulateNode(e.Node, e.Node.Name + info.Name);
                else
                    PopulateNode(e.Node, e.Node.Name + "\\" + info.Name);
            }

            this.PopulateNodeFiles(e.Node, e.Node.Name);
        }
        /// <summary>
        /// Called when the user clicks either on a treenode, or on the + / - beside it
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.TreeNodeMouseClickEventArgs"/> instance containing the event data.</param>
        void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            this.config.AppSettings.Settings["LastChosenNode"].Value = e.Node.Name;
        }
        /// <summary>
        /// Called when Tools -> Options is clicked
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SettingsMenu menu = new SettingsMenu();
            menu.ShowDialog();
        }
        /// <summary>
        /// Called when Help -> About is clicked
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutBox aboutBox = new AboutBox();
            aboutBox.ShowDialog();
        }
        /// <summary>
        /// Handles the Click event of the button1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnGo_Click(object sender, EventArgs e)
        {
            if (btnGo.Text == "Stop")
            {
                convert.Stop();
                this.btnGo.Text = "Go";
                foreach(DataGridViewRow row in this.dataGridView1.Rows)
                {
                    DataGridViewCell progress = row.Cells["Progress"];
                    if (progress.Value.ToString() != "Finished")
                        progress.Value = "";
                }
                return;
            }

            if (this.mediaFiles.Count < 1)
                return;

            ParameterizedThreadStart start = new ParameterizedThreadStart(convert.ConvertMediaFile);
         
            Thread worker = new Thread(start);
       
            this.workerThreads.Add(worker);
            for(int i = 0; i < this.mediaFiles.Count; i++)
            {
                string progress = (string)this.dataGridView1["Progress", i].Value;
                if (progress != "Finished")
                {
                    FileInfo inputFile = new FileInfo(this.mediaFiles[i].InputFilename);
                    FileInfo outputFile = new FileInfo(this.mediaFiles[i].OutputFilename);

                    if (inputFile.Exists == false)
                    {
                        this.dataGridView1["Progress", i].Value = "File not found";
                        continue;
                    }

                    if (outputFile.Exists)
                    {
                        this.dataGridView1["Progess", i].Value = "Output already exists";
                        continue;
                    }
                    worker.Start(this.mediaFiles[i]);
                    this.toolStripStatusLabel1.Text = this.mediaFiles[i].ShortFilename + " started.";
                    this.dataGridView1["Output", i].ReadOnly = true;
                    this.btnGo.Text = "Stop";
                    break;
                }
            }

        }
        /// <summary>
        /// Handles the ConversionPercentageChanged event of the convert control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="ConversionInterface.ConvertMedia.ConversionEventArgs"/> instance containing the event data.</param>
        void convert_ConversionPercentageChanged(object sender, ConvertMedia.ConversionEventArgs e)
        {
            
            foreach (DataGridViewRow row in this.dataGridView1.Rows)
            {
                MediaFile dataFile = (MediaFile)row.DataBoundItem;
                if (dataFile.ShortFilename == e.MediaFile.ShortFilename && dataFile.TargetDevice == e.MediaFile.TargetDevice)
                {
                    row.Cells["Progress"].Value = e.MediaFile.PercentComplete.ToString() + "%";
                }
            }
        }
        /// <summary>
        /// Handles the ConversionComplete event of the convert control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="ConversionInterface.ConvertMedia.ConversionEventArgs"/> instance containing the event data.</param>
        void convert_ConversionComplete(object sender, ConvertMedia.ConversionEventArgs e)
        {
            if (this.btnGo.InvokeRequired)
                this.btnGo.Invoke(new ConvertMedia.OnConversionComplete(CheckGridForNewFiles),new object[] {sender, e});
            else
                this.CheckGridForNewFiles(sender, e);
        }
        /// <summary>
        /// Called when a media file enters a different stage
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="ConversionInterface.ConvertMedia.ConversionEventArgs"/> instance containing the event data.</param>
        void convert_ConversionStageChanged(object sender, ConvertMedia.ConversionEventArgs e)
        {
            foreach (DataGridViewRow row in this.dataGridView1.Rows)
            {
                if (row.DataBoundItem == e.MediaFile)
                {
                    row.Cells["Stage"].Value = e.MediaFile.StageInfo;
                }
            }
        }
        /// <summary>
        /// Handles the Click event of the btnClean control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnClean_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < this.mediaFiles.Count; i++)
            {
                if (mediaFiles[i].PercentComplete == 100)
                    this.mediaFiles.RemoveAt(i);
            }

            //this.PopulateGrid();
        }
        /// <summary>
        /// Handles the Click event of the deleteToolStripMenuItem control.  Called when the grid is right clicked -> Delete
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in this.dataGridView1.SelectedRows)
            {
                MediaFile file = (MediaFile)row.DataBoundItem;

                if (!this.mediaFiles.Remove(file))
                {
                    throw new Exception("Failed to remove file.");
                }
                this.persistence.DeleteJob(file);
            }

            //this.PopulateGrid();
        }
        /// <summary>
        /// Handles the Click event of the moveUpToolStripMenuItem control.  Called on right click grid -> Move Up
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void moveUpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in this.dataGridView1.SelectedRows)
            {
                int index = row.Index;
                if (index > 0)
                {
                    MediaFile temp = this.mediaFiles[index];
                    MediaFile temp2 = this.mediaFiles[index - 1];
                    this.mediaFiles[index] = temp2;
                    this.mediaFiles[index - 1] = temp;
                }
            }

            //this.PopulateGrid();
        }
        /// <summary>
        /// Handles the Click event of the moveDownToolStripMenuItem control.  Call when the grid is right clicked -> Move Down
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void moveDownToolStripMenuItem_Click(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in this.dataGridView1.SelectedRows)
            {
                int index = row.Index;
                if (index < this.dataGridView1.Rows.Count - 1)
                {
                    MediaFile temp = this.mediaFiles[index];
                    MediaFile temp2 = this.mediaFiles[index + 1];
                    this.mediaFiles[index] = temp2;
                    this.mediaFiles[index + 1] = temp;
                }
            }

            //this.PopulateGrid();
        }
        /// <summary>
        /// Handles the CellBeginEdit event of the dataGridView1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellCancelEventArgs"/> instance containing the event data.</param>
        void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Output")
            {
                this.tempOutputFilename = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value.ToString();
            }
        }
        /// <summary>
        /// Handles the CellEndEdit event of the dataGridView1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellEventArgs"/> instance containing the event data.</param>
        void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            MediaFile file = (MediaFile)this.dataGridView1.Rows[e.RowIndex].DataBoundItem;
            if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Output")
            {
                
                object name = this.dataGridView1["Output", e.RowIndex].Value;

                if (name == null || name.ToString().Trim() == "")
                {
                    this.dataGridView1[e.ColumnIndex, e.RowIndex].Value = this.tempOutputFilename;
                    MessageBox.Show("You must choose a valid filename", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
                else
                {
                    file.OutputFilename = name.ToString();
                }
            }
            else if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Target")
            {
                object o = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value;
                object o2 = System.Enum.Parse(typeof(ConvertMedia.ConversionTarget), o.ToString());
                file.TargetDevice = (ConvertMedia.ConversionTarget)o2;
            }
            else if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Audio")
            {
                object o = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value;
                foreach (AudioTrack track in file.AvailableAudio)
                {
                    if (track.Language == (MediaFile.MediaLanguage)o)
                    {
                        file.ChosenAudio = track;
                        break;
                    }
                }
            }
            else if (this.dataGridView1.Columns[e.ColumnIndex].Name == "Subtitle")
            {
                object o = this.dataGridView1[e.ColumnIndex, e.RowIndex].Value;
                foreach (SubtitleTrack track in file.AvailableSubs)
                {
                    if (track.Language == (MediaFile.MediaLanguage)o)
                    {
                        file.ChosenSub = track;
                        break;
                    }
                }
            }
        }
        void dataGridView1_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            //we intentionally do nothing here because it appears there is a 
            //bug within .Net 3.5 where combo boxes keep throwing data errors 
            //when it shouldn't
            if (e.Context == (DataGridViewDataErrorContexts.Formatting | DataGridViewDataErrorContexts.PreferredSize))
            {

                e.ThrowException = false;
            }
        }
        #endregion

        #region Utility Functions
        /// <summary>
        /// Populates the treeview with folders from the system.
        /// </summary>
        private void PopulateTree()
        {
            treeView1.ImageList = imageList;
            treeView1.Nodes.Add(System.Environment.MachineName, System.Environment.MachineName, 0);

            DriveInfo[] driveList = DriveInfo.GetDrives();

            bool showNetworkDrives = this.GetConfig("ShowNetworkDrives") == "true";

            foreach (DriveInfo drive in driveList)
            {
                if (drive.DriveType == DriveType.CDRom || drive.DriveType == DriveType.Unknown)
                    continue;

                if (drive.DriveType == DriveType.Network && showNetworkDrives == false)
                    continue;

                string driveName = drive.Name.ToString();
                TreeNode parent = treeView1.Nodes.Add(driveName, driveName);
                parent.Nodes.Add("dummy", "");

                DirectoryInfo directoryInfo = new DirectoryInfo(drive.Name);

                switch (drive.DriveType)
                {
                    case DriveType.Fixed:
                        parent.ImageIndex = 2;
                        parent.SelectedImageIndex = 2;
                        break;
                    case DriveType.Network:
                        parent.ImageIndex = 3;
                        parent.SelectedImageIndex = 3;
                        break;
                    case DriveType.Removable:
                        parent.ImageIndex = 4;
                        parent.SelectedImageIndex = 4;
                        break;
                }

            }

            treeView1.Update();
        }
        /// <summary>
        /// Populates an individual tree node based on a folder or filename
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="path">The path.</param>
        private void PopulateNode(TreeNode parent, string path)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(path);

            if (((directoryInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) ||
                ((directoryInfo.Attributes & FileAttributes.System) == FileAttributes.System))
                return;

            if (!directoryInfo.Exists)
                return;


            TreeNode newNode = parent.Nodes.Add(path, directoryInfo.Name, 0, 0);
            newNode.Nodes.Add("dummy", "");
        }
        /// <summary>
        /// Takes a treenode, looks for all applicable video files under that directory, and populates them as new children nodes
        /// </summary>
        /// <param name="parent">The parent.</param>
        /// <param name="path">The path.</param>
        private void PopulateNodeFiles(TreeNode parent, string path)
        {
            if (parent.Nodes.Count > 1 && parent.FirstNode.Name != "dummy" && parent.Parent != null)
                return;
            List<FileInfo> files = null;

            try
            {
                files = this.GetFiles(path);
            }
            catch (IOException)
            {
                return;
            }

            foreach (FileInfo info in files)
            {
                if (((info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) ||
                    ((info.Attributes & FileAttributes.System) == FileAttributes.System))
                    continue;
                if(parent.Parent != null)
                    parent.Nodes.Add(path + "\\" + info.Name, info.Name, 5, 5);
                else
                    parent.Nodes.Add(path + info.Name, info.Name, 5, 5);
            }
        }
        /// <summary>
        /// Populates the grid by binding it to the collection of media files
        /// </summary>
        private void PopulateGrid()
        {
            this.dataGridView1.AutoGenerateColumns = false;
            this.dataGridView1.DataSource = this.mediaFiles;

            foreach (DataGridViewRow row in this.dataGridView1.Rows)
            {
                MediaFile file = (MediaFile)row.DataBoundItem;
                if (file.PercentComplete == 100)
                {
                    row.Cells["Progress"].Value = "Finished";
                }
            }
        }
        /// <summary>
        /// Checks the grid for new files.  Meant to be called after an encoding thread is complete, to kick off a new job
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="ConversionInterface.ConvertMedia.ConversionEventArgs"/> instance containing the event data.</param>
        private void CheckGridForNewFiles(object sender, ConvertMedia.ConversionEventArgs e)
        {
            bool finished = true;
            for (int i = 0; i < this.dataGridView1.Rows.Count; i++)
            {
                MediaFile dataFile = (MediaFile)this.dataGridView1.Rows[i].DataBoundItem;
                if (dataFile.ShortFilename == e.MediaFile.ShortFilename && dataFile.TargetDevice == e.MediaFile.TargetDevice)
                {
                    if (e.MediaFile.PercentComplete == 100)
                    {
                        this.dataGridView1.Rows[i].Cells["Progress"].Value = "Finished";
                        this.dataGridView1.Rows[i].Cells["Stage"].Value = "";
                        //get the next file
                        if (this.dataGridView1.Rows.Count > i + 1)
                        {
                            MediaFile nextFile = (MediaFile)this.dataGridView1.Rows[i + 1].DataBoundItem;
                            ParameterizedThreadStart start = new ParameterizedThreadStart(convert.ConvertMediaFile);
                            this.dataGridView1["Output", i].ReadOnly = true;
                            Thread t = new Thread(start);
                            this.workerThreads.Add(t);
                            t.Start(nextFile);
                        }
                    }
                    else
                    {
                        this.dataGridView1.Rows[i].Cells["Progress"].Value = "Failed";
                        this.dataGridView1.Rows[i].Cells["Stage"].Value = "";
                    }
                }
                else
                {
                    if (dataFile.PercentComplete != 100)
                        finished = false;
                }
            }

            if (finished)
            {
                this.btnGo.Text = "Go!";
            }
            
        }
        /// <summary>
        /// Releases all resources used by the <see cref="T:System.ComponentModel.Component"/>.
        /// </summary>
        public void CleanUp()
        {
            if (!disposed)
            {
                foreach (Thread t in this.workerThreads)
                {
                    t.Abort();
                }
                //save the config file
                //config.Save(ConfigurationSaveMode.Modified);
                //try to shut off mencoder forcefully
                this.convert.Dispose();
                this.disposed = true;
            }
        }
        /// <summary>
        /// By passing in a directory path, you are returned a list of the valid media files in that directory.
        /// </summary>
        /// <param name="directory">The directory.</param>
        /// <returns></returns>
        private List<FileInfo> GetFiles(string directory)
        {
            DirectoryInfo dInfo = new DirectoryInfo(directory);
            List<FileInfo> files = new List<FileInfo>();
            if (dInfo.Exists == false)
                throw new ArgumentException("Directory does not exist:" + directory);

            string[] validExtensions = new string[] { "*.mkv", "*.avi", "*.mp4", "*.ogm" };

            foreach (string extension in validExtensions)
            {
                files.AddRange(dInfo.GetFiles(extension, SearchOption.TopDirectoryOnly));
            }

            return files;
        }
        #endregion
    }
}
